#ifndef _CSETYPES_H_CSEAPI_
#define _CSETYPES_H_CSEAPI_

#include <stdlib.h>
#include <stdarg.h>
#include <assert.h>

#ifdef _WIN32
  #undef __BIT64SYS__

  #ifndef __WINDOWS__
    #define __WINDOWS__
  #endif
#endif

#ifdef _WIN64
  #ifndef _WIN32
    #define _WIN32   // define it for compatibility reasons
  #endif

  #ifndef __BIT64SYS__
    #define __BIT64SYS__
  #endif

  #ifndef __WINDOWS__
    #define __WINDOWS__
  #endif
#endif

#if defined(_UNICODE)
  #undef CSE_USE_UNICODE
  #define CSE_USE_UNICODE          1
#else
  #ifndef CSE_USE_UNICODE
    #define CSE_USE_UNICODE        0
  #endif
#endif

#if CSE_USE_UNICODE
  #ifndef _UNICODE
    #define _UNICODE
  #endif
#endif

// CSE API version and feature: V2.1.0.0
#define CSE_API_VERSION            0x02010000
#if !defined(_UNICODE)
  #define CSE_FEATURE_FLAG         0x00000000     // SBCS
#else
  #define CSE_FEATURE_FLAG         0x00000001     // unicode
#endif

#ifndef NULL
  #ifdef  __cplusplus
    #define NULL                   0L
  #else
    #define NULL                   ((void *)0)
  #endif
#endif

#ifndef true
  #define true                     1
#endif
#ifndef false
  #define false                    0
#endif

#if defined(__WINDOWS__)
  #if defined(_MSC_VER) && _MSC_VER >= 1200 // support VC6 and later version
    #define __VISUALC__            _MSC_VER
  #else
    #undef __VISUALC__
  #endif
#endif

#if defined(__VISUALC__)
  // rename usage of "struct tm" that declared in time.h
  #define struct_tm struct tm
  
  #ifndef _WCHAR_T_DEFINED
    typedef unsigned short         wchar_t;
    #define _WCHAR_T_DEFINED
  #endif

  #ifndef _VA_LIST_DEFINED
    typedef char*                  va_list;
    #define _VA_LIST_DEFINED
  #endif

  typedef char                     TChar;
  typedef wchar_t                  TWchar;

  typedef char                     TInt8;
  typedef unsigned char            TUint8;
  typedef short                    TInt16;
  typedef unsigned short           TUint16;
  typedef __int32                  TInt32;
  typedef unsigned __int32         TUint32;
  typedef __int64                  TInt64;
  typedef unsigned __int64         TUint64;
  typedef float                    TFloat;
  typedef double                   TDouble;

  typedef long                     TLong;
  typedef unsigned long            TUlong;
    
  #ifdef __cplusplus
    typedef bool                   TBool;
  #else
    typedef TInt8                  TBool;
  #endif

  typedef size_t                   TSize_t;
  typedef void                     TVoid;

  #ifdef _UNICODE
    typedef wchar_t                TXchar;
  #else
    typedef char                   TXchar;
  #endif

  // sizeof(TInt) in 32-bits system is 4 bytes, and in 64-bits is 8
  #ifdef _WIN64
    typedef long                   TInt;
    typedef unsigned long          TUint;
  #else
    typedef int                    TInt;
    typedef unsigned int           TUint;
  #endif

  // sizeof(TWint) is 8 bytes both in 32-bits and 64-bits system
  typedef __int64                  TWint;
  typedef unsigned __int64         TUwint;
    
#elif defined(__GNUC__)
  #if (__GNUC__ < 2) || (__GNUC__ == 2 && __GNUC_MINOR__ < 96)
    #error "GCC compiler version too low, not support wchar_t."
  #endif
  
  typedef char                     TChar;
  typedef wchar_t                  TWchar;

  typedef char                     TInt8;
  typedef unsigned char            TUint8;
  typedef short                    TInt16;
  typedef unsigned short           TUint16;
  typedef int                      TInt32;
  typedef unsigned int             TUint32;
  typedef long long                TInt64;
  typedef unsigned long long       TUint64;
  typedef float                    TFloat;
  typedef double                   TDouble;

  typedef long                     TLong;
  typedef unsigned long            TUlong;

  typedef bool                     TBool;

  typedef size_t                   TSize_t;
  typedef void                     TVoid;

  #ifdef _UNICODE
    typedef wchar_t                TXchar;
  #else
    typedef char                   TXchar;
  #endif

  // sizeof(TInt) in 32-bits system is 4 bytes, and in 64-bits is 8
  #if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64)
    typedef long                   TInt;
    typedef unsigned long          TUint;
  #else
    typedef int                    TInt;
    typedef unsigned int           TUint;
  #endif

  // sizeof(TWint) is 8 bytes both in 32-bits and 64-bits system
  typedef long long                TWint;
  typedef unsigned long long       TUwint;
#endif

typedef enum _UNUSED_ENUM {}       TEnumType;
typedef TVoid*                     TVoidp;
typedef TChar*                     TCharp;
typedef TWchar*                    TWcharp;
typedef TXchar*                    TXcharp;
typedef TInt32*                    TInt32p;
typedef TInt*                      TIntp;
typedef TLong*                     TLongp;

// size of TInt16, TInt32, TInt64 should correct
// otherwize, error will report at compile time
struct int_type_is_ok {int value: sizeof(TInt16)==2 && sizeof(TInt32)==4 && sizeof(TInt64)==8;};

// if sizeof(TInt) != sizeof(void *), error will report at compile time
// CSE system use TInt to hold symbol address also!
struct TInt_same_size_to {int a_pointer: sizeof(TInt) == sizeof(void *);};

// if sizeof(TInt) is not 4 or 8, error will report at compile time
// sizeof(TInt) == 4 is NORMAL_INT_SYS, 8 is LARGE_INT_SYS
struct TInt_must_be {int TInt32_or_TInt64: sizeof(TInt)==4 || sizeof(TInt)==8;};

#define CSE_INT_SIZE               sizeof(TInt)

#ifndef SIZE_T_MAX
  #define SIZE_T_MAX               ((size_t) -1)
#endif

#define CSE_CONCAT(text, post)     text ## post

#ifndef _T
  #if !CSE_USE_UNICODE
    #define _T(x)                  x
  #else
    #define _T(x)                  CSE_CONCAT(L,x)
  #endif
#endif

#ifndef _A
  #define _A(x)                    x
#endif

#ifndef _U
  #define _U(x)                    CSE_CONCAT(L,x)
#endif

#define CseFunc2C(f)               ((void*) &f)
#define PASS()

typedef struct
{
    const TXchar *ErrType;
    const TXchar *ErrDesc; 
    TInt32 ErrFlag;
} TAbsExcept;

#ifndef CSE_USE_PLATFORM
  #ifdef _DEBUG
    #define ASSERT_TRUE(cond)          assert(cond)
    #define ASSERT_MSG(cond,desc)      assert(cond)
  #else
    #define ASSERT_TRUE(cond)
    #define ASSERT_MSG(cond,desc)
  #endif

  #define WAIT_TO_DO()                 assert(0)

  #define CHECK_TRUE(cond)             assert(cond)
  #define CHECK_MSG(cond,desc)         assert(cond)
#endif

#define S_ATTR(obj,AClass,attr)        (((AClass *)&(obj))->attr)
#define S_PATTR(pObj,AClass,attr)      (((AClass *)pObj)->attr)
#define S_FUNC(obj,AClass,attr)        (((AClass *)&(obj))->func->attr)
#define S_PFUNC(pObj,AClass,attr)      (((AClass *)pObj)->func->attr)

#if defined(__cplusplus) && !defined(IN_EXTERNC_OF_CPP)
  template <class T> class TCObjHolder: public T
  { public:
    ~TCObjHolder() { this->func->free(this); }
  };
  #define OOC_TYPEDEF(T)  typedef TCObjHolder<class T##__> T
  #define OOC_TYPEDEF2(T) typedef TCObjHolder<struct T##__> T

  class IAbstract
  { public:
    IAbstract() { }
  };
  #define I_FUNC(obj,Func)             (((IAbstract *) &(obj))->*Func)
  #define I_PFUNC(pObj,Func)           (((IAbstract *) pObj)->*Func)
#else
  #define OOC_TYPEDEF(T)  typedef struct T##__ T
  #define OOC_TYPEDEF2(T) typedef struct T##__ T
#endif

#endif
